package com.jasmine.bjstkserver.server.folder;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.jasmine.auth.util.AuthUtil;
import com.jasmine.bjstkserver.mapper.ArticleDraftMapper;
import com.jasmine.bjstkserver.mapper.FolderMapper;
import com.jasmine.bjstkserver.mapper.PictureMapper;
import com.jasmine.bjstkserver.server.folder.model.FolderEntity;
import com.jasmine.bjstkserver.server.folder.model.FolderReq;
import com.jasmine.bjstkserver.server.folder.model.FolderTreeRes;
import com.jasmine.core.constants.BjsConstants;
import com.jasmine.core.util.BeanUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author jasmineXz
 */
@Service
public class FolderServiceImpl implements FolderService {

    @Autowired
    private FolderMapper folderMapper;

    @Autowired
    private PictureMapper pictureMapper;

    @Autowired
    private ArticleDraftMapper articleDraftMapper;


    @Override
    public List<FolderTreeRes> findList(FolderReq folder) {
        return folderMapper.findList(folder);
    }


    /**
     * 树状列表
     */
    @Override
    @Cacheable(cacheNames = BjsConstants.Redis.FOLDER, key = "'userid_' + #folder.getUserId() + '_type_' + #folder.getType()")
    public List<FolderTreeRes> findTree(FolderReq folder) {
        final List<FolderTreeRes> all = folderMapper.findList(folder);
        Objects.requireNonNull(all);
        List<FolderTreeRes> root = all.stream().filter(p -> p.getFolderPid() == 0).collect(Collectors.toList());
        root.parallelStream().forEach(item -> setChild(item, all));
        return root;
    }


    /**
     * 查询文件夹信息
     * @param folder 文件夹ID
     * @return 文件夹信息
     */
    @Override
    public FolderEntity findOne(FolderReq folder) {
        return folderMapper.findOne(folder);
    }


    /**
     * 新增文件夹
     */
    @Override
    @CacheEvict(cacheNames = BjsConstants.Redis.FOLDER, key = "'userid_' + #folder.getUserId() + '_type_' + #folder.getType()")
    public Integer insert(FolderEntity folder) {
        folder.setFolderId(null);
        if(null == folder.getFolderPid()) {
            folder.setFolderPid(0);
        }
        if (StrUtil.isNotBlank(folder.getUploadPath())) {
            folder.setUploadPath(StrUtil.appendIfMissingIgnoreCase(folder.getUploadPath(),"/","/"));
        }
        folder.setCreTime(LocalDateTime.now());
        return folderMapper.insertSelective(folder);
    }


    /**
     * 修改文件夹
     */
    @Override
    @CacheEvict(cacheNames = BjsConstants.Redis.FOLDER, key = "'userid_' + #folder.getUserId() + '_type_' + #folder.getType()")
    public Integer updateOne(FolderEntity folder) {
        if(null == folder.getFolderPid()) {
            folder.setFolderPid(0);
        }
        if (folder.getFolderId().equals(folder.getFolderPid())) {
            throw new IllegalArgumentException("父文件夹不能是自己");
        }
        if (findChildId(folder.getFolderId()).contains(folder.getFolderPid())) {
            throw new IllegalArgumentException("父文件夹不能是自己或自己的子文件夹");
        }
        if (StrUtil.isNotBlank(folder.getUploadPath())) {
            folder.setUploadPath(StrUtil.appendIfMissingIgnoreCase(folder.getUploadPath(),"/","/"));
        }

        return folderMapper.updateByPrimaryKeySelective(folder);
    }


    /**
     * 删除文件夹
     * 将此文件夹下的文件设置为无文件夹文件
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = BjsConstants.Redis.FOLDER, key = "'userid_' + #folder.getUserId() + '_type_' + #folder.getType()")
    public Integer deleteOne(FolderReq folder) throws Exception {
        FolderEntity fold = folderMapper.selectByPrimaryKey(BeanUtil.copyObject(folder, FolderEntity.class));
        if (fold == null) {
            return 0;
        }

        // 1.获取文件夹及子文件夹ID
        List<Integer> folderIds = findChildId(fold.getFolderId());

        if (CollectionUtil.isEmpty(folderIds)) {
            return 0;
        }

        // 2. 重置文件夹及子文件夹下的文件到未分类中
        folderIds.forEach(folderId -> {
            pictureMapper.resetFolder(AuthUtil.getUserId(),folderId);
            articleDraftMapper.resetFolder(AuthUtil.getUserId(),folderId);
        });

        // 3.删除文件夹及子文件夹
        return folderMapper.deletes(FolderReq.builder().folderIds(folderIds).build());
    }





























    /**
     * 构造树状列表
     */
    private void setChild(FolderTreeRes p, List<FolderTreeRes> folder) {
        //将集合中自己去除
        List<FolderTreeRes> child =
                folder.parallelStream()
                    .filter(a -> a.getFolderPid().equals(p.getFolderId()))
                    .collect(Collectors.toList());
        p.setChild(child);
        if (!CollectionUtils.isEmpty(child)) {
            child.parallelStream().forEach(c -> {
                setChild(c, folder); //递归设置子元素
            });
        }
    }

    /**
     * 获取文件夹下子文件夹
     * @param folderId 文件夹ID
     * @return 子文件夹ID集合
     */
    private List<Integer> findChildId(Integer folderId){
        List<Integer> folders = new ArrayList<>();
        folders.add(folderId);
        return recursion(folderId,folders);
    }

    /**
     * 递归查询子文件夹
     * @param folderId 文件夹ID
     * @param list 放入文件夹列表
     * @return 文件夹ID列表
     */
    private List<Integer> recursion(Integer folderId,List<Integer> list) {
        folderMapper.findList(FolderReq.builder().folderPid(folderId).build())
            .forEach(item -> {
                list.add(item.getFolderId());
                recursion(item.getFolderId(), list);
            }
        );
        return list;
    }
}
